<?php

//free
//query
//execute
//close
//escapeString

//startTrans
//commit
//rollback


class Db
{

    static public $dbObject = array();
    public $linkID = "";
    public $_linkID = "";
    public $queryID = "";
    public $numRows = "";
    public $numCols = "";
    public $lastInsID = "";
    public $_error;
    public $queryStr;
    public $transTimes;

    /**
     * 架构函数 读取数据库配置信息
     *
     * @access private
     *
     * @param  array  $config  数据库配置数组
     */
    private function __construct($config, $group)
    {
        if (!empty($config[$group])) {
            $this->connect($config[$group], $group);
        } else {
            exit("config not empty!");
        }
    }

    public static function getObject($config = '', $group = "default")
    {
        if (!isset(static::$dbObject[$group])) {
            static::$dbObject[$group] = new self($config, $group);
        } else {
            if (!isset(static::$dbObject[$group]->linkID[$group])) {
                static::$dbObject[$group]->connect($config[$group], $group);
            }
        }
        return static::$dbObject[$group];
    }

    /**
     * 连接数据库方法
     *
     * @access public
     */
    public function connect($config = '', $linkNum = 0)
    {
        $this->linkID[$linkNum] = new mysqli($config['hostname'], $config['username'], $config['password'],
            $config['database'], $config['hostport'] ? intval($config['hostport']) : 3306);
        if (mysqli_connect_errno()) {
            $this->_error = mysqli_connect_error();
            $this->logError();
        }
        // 设置数据库编码
        $this->linkID[$linkNum]->query("SET NAMES UTF8");
        $this->_linkID = $this->linkID[$linkNum];
    }

    /**
     * 释放查询结果
     *
     * @access public
     */
    public function free()
    {
        if (!empty($this->queryID)) {
            $this->queryID->free_result();
            $this->queryID = null;
        }

    }

    /**
     * 执行查询 返回数据集
     *
     * @access public
     *
     * @param  string  $str  sql指令
     *
     * @return mixed
     */
    public function query($str = "show tables")
    {
        if (!$this->_linkID) {
            return false;
        }
        $this->queryStr = $str;
        //释放前次的查询结果
        if ($this->queryID) {
            $this->free();
        }

        $this->queryID = $this->_linkID->query($str);
        // 对存储过程改进
        if ($this->_linkID->more_results()) {
            while (($res = $this->_linkID->next_result()) != null) {
                $res->free_result();
            }
        }
        if (false === $this->queryID) {
            $this->_error = mysqli_error($this->_linkID);
            $this->logError();
            return false;
        } else {
            $this->numRows = $this->queryID->num_rows;
            $this->numCols = $this->queryID->field_count;
            return $this->getAll();
        }
    }

    /**
     * 执行语句
     *
     * @access public
     *
     * @param  string  $str  sql指令
     *
     * @return integer
     */
    public function execute($str = "show tables")
    {
        if (!$this->_linkID) {
            return false;
        }
        $this->queryStr = $str;
        //释放前次的查询结果
        if ($this->queryID) {
            $this->free();
        }
        $result = $this->_linkID->query($str);
        if (false === $result) {
            $this->_error = mysqli_error($this->_linkID);
            $this->logError();
            return false;
        } else {
            $this->numRows   = $this->_linkID->affected_rows;
            $this->lastInsID = $this->_linkID->insert_id;
            return $this->numRows;
        }
    }

    /**
     * 启动事务
     *
     * @access public
     * @return void
     */
    public function startTrans()
    {
        //数据rollback 支持
        if ($this->transTimes == 0) {
            $this->_linkID->autocommit(false);
        }
        $this->transTimes++;
        return;
    }

    /**
     * 用于非自动提交状态下面的查询提交
     *
     * @access public
     * @return boolen
     */
    public function commit()
    {
        if ($this->transTimes > 0) {
            $result = $this->_linkID->commit();
            $this->_linkID->autocommit(true);
            $this->transTimes = 0;
            if (!$result) {
                return false;
            }
        }
        return true;
    }

    /**
     * 事务回滚
     *
     * @access public
     * @return boolen
     */
    public function rollback()
    {
        if ($this->transTimes > 0) {
            $result           = $this->_linkID->rollback();
            $this->transTimes = 0;
            if (!$result) {
                return false;
            }
        }
        return true;
    }

    /**
     * 获得所有的查询数据
     *
     * @access private
     *
     * @param  string  $sql  sql语句
     *
     * @return array
     */
    private function getAll()
    {
        //返回数据集
        $result = array();
        if ($this->numRows > 0) {
            //返回数据集
            for ($i = 0; $i < $this->numRows; $i++) {
                $result[$i] = $this->queryID->fetch_assoc();
            }
            $this->queryID->data_seek(0);
        }
        return $result;
    }

    /**
     * 关闭数据库
     *
     * @access public
     * @return volid
     */
    public function close($linkNum = 'default')
    {
        if ($this->_linkID) {
            $this->_linkID->close();
        }
        $this->_linkID = null;
        unset(self::$dbObject[$linkNum]);
    }

    /**
     * SQL指令安全过滤
     *
     * @static
     * @access public
     *
     * @param  string  $str  SQL指令
     *
     * @return string
     */
    public function escapeString($str)
    {
        if ($this->_linkID) {
            return $this->_linkID->real_escape_string($str);
        } else {
            return addslashes($str);
        }
    }

    /**
     * 获取上一次查询的错误信息
     *
     * @return string 错误信息
     */
    public function getError()
    {
        return $this->_error;
    }

    /**
     * 记录错误日志到文件
     */
    private function logError()
    {
        $str = '[SQL ERR]'.$this->_error.' SQL:'.$this->queryStr."\n";
        Log::warn($str);
    }
}

